package org.jim.connector.command;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import com.huiyun.project.common.core.constant.SecurityConstants;
import com.huiyun.project.common.core.util.fn.FunctionUtils;
import com.huiyun.project.im.consts.ImCsSessionConst;
import com.huiyun.project.im.server.client.feign.RemoteCsSessionService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.jim.core.ImConst;
import org.jim.core.ImPacket;
import org.jim.core.cache.redis.JedisTemplate;
import org.jim.core.helper.IUserHelper;
import org.jim.core.helper.cs.ICsChatHelper;
import org.jim.core.helper.cs.ICsSessionHelper;
import org.jim.core.packets.pub.consts.Command;
import org.jim.core.packets.RespBody;
import org.jim.core.packets.cs.session.vo.*;
import org.jim.core.utils.KeyUtil;
import org.jim.server.JimServerAPI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * @FileName:
 * @Description: 客服分配, 基于同一个分布式锁
 * @Author linjie
 * @Date 2020/8/78:11 PM
 * @Version 4.0.0
 */
@Component
public class CsAllocHelper implements ImConst {

    @Autowired
    private RemoteCsSessionService remoteCsSessionService;
    @Autowired
    private ICsChatHelper iCsChatHelper;
    @Autowired
    private IUserHelper userHelper;
    @Autowired
    private ICsSessionHelper iCsSessionHelper;

    /**
     * 客服登陆的时候初始化分配,客服会创建session
     */
    public void initAlloc(String tenantId, String csOrgId) {
        try {
            JimCsSessionConfigResp config = FunctionUtils.getOkData(remoteCsSessionService.getConfig(tenantId, SecurityConstants.FROM_IN));
            //首次就绪分配的最大人数
            Integer max = config.getInitMaxUser();
            //队列会话分配
        } catch (Exception e) {
            //
        }
        //获取队列用户
    }


    /**
     * 离线会话定时随机分配
     */
    public void offlineAlloc() {
        try {
//            String csTenantId = "";
//            String csOrgId = "";

            List<JimCsSessionConfigResp> configRespList = FunctionUtils.getOkData(remoteCsSessionService.getCsConfig(SecurityConstants.FROM_IN));
            if (CollectionUtil.isEmpty(configRespList)) {
                return;
            }
            for (JimCsSessionConfigResp config : configRespList) {
//            JimCsSessionConfigResp config = FunctionUtils.getOkData(remoteCsSessionService.getConfig(csTenantId, SecurityConstants.FROM_IN));
                //首次就绪分配的最大人数
                Integer max = config.getInitMaxUser();
                //获取离线会话(没有客服在的时候,才会有离线会话)
                String key = KeyUtil.formatKey(ImConst.MSG_KEY.CS_CS_OFFLINE, "csTenantId", config.getImTenantId(), "userId", null);
                List<String> keys = new ArrayList(JedisTemplate.me().keys(PUSH + SUFFIX + key));
                //离线会话分配
                if (CollUtil.isNotEmpty(keys)) {
                    //获取所有在线的有空闲的客服,此处暂未实现
                    List<String> userIdList = userHelper.getOnlineCsList(config.getImTenantId(), "");
                    //存储分配结果
                    Map<String, List<String>> result = new HashMap<>();
                    if (CollUtil.isNotEmpty(userIdList)) {
                        //轮训分配
                        int count = keys.size() > userIdList.size() ? keys.size() : userIdList.size();
                        int uNum = 0;
                        int oNum = 0;
                        for (int i = 0; i < count; i++) {
                            List<String> offlineKeys = result.get(userIdList.get(uNum));
                            if (offlineKeys == null) {
                                offlineKeys = new ArrayList<>();
                                result.put(userIdList.get(uNum), offlineKeys);
                            }
                            offlineKeys.add(keys.get(oNum));
                            uNum = uNum < userIdList.size() ? uNum++ : 0;
                            oNum++;
                            if (oNum >= keys.size()) {
                                //分配完成了
                                break;
                            }
                        }
                    }
                    //根据分配结果,创建会话
                    if (CollUtil.isNotEmpty(result)) {
                        List<JimCsCreateSessionResp> respList;
                        for (String csId : result.keySet()) {//循环客服 map
                            respList = new ArrayList<>();
                            List<String> redisKey = result.get(csId);
                            JimCsCreateSessionReq req = new JimCsCreateSessionReq();
                            req.setCsId(csId);
                            req.setCsOrgId("1");//技能组默认
                            req.setUserSource(1)
                                    .setDevice(1)
                                    .setDevicePlatform(1)
                                    .setIp("0.0.0.0")
                                    .setAppKey("333");
                            for (String rKey : redisKey) {//循环 redis key
                                String[] keyarr = rKey.split(":");
                                req.setCsTenantId(keyarr[2]);
                                req.setUserId(keyarr[3]);
                                //创建session
                                JimCsCreateSessionResp resp = iCsSessionHelper.create(req);
                                //设置离线消息
                                resp.setData(JedisTemplate.me().sorSetRangeByScore(rKey,Double.MIN_VALUE,Double.MAX_VALUE));
                                respList.add(resp);
                            }
                            //会话变动通知
                            JimCsChangeSessionResp changeSessionResp = new JimCsChangeSessionResp();
                            changeSessionResp.setChangeType(ImCsSessionConst.SESSION_CHANGE_TYPE.OFFLINE_MESSAGE.getValue());//离线消息
                            changeSessionResp.setData(respList);
                            ImPacket chatPacket = new ImPacket(Command.COMMAND_CHANGE_SESSION_RESP, new RespBody(Command.COMMAND_CHANGE_SESSION_RESP, changeSessionResp).toByte());
                            //chatPacket.setSynSeq(packet.getSynSeq());
                            //发送到对应的客服
                            JimServerAPI.sendToUser(csId, chatPacket);
                            //移除对应人 离线消息
                            JedisTemplate.me().delKeys(redisKey.toArray(new String[redisKey.size()]));
                        }
                    }
                }
            }
        } catch (Exception e) {

        }

    }

    /**
     * 用户连接的时候分配客服并创建会话
     *
     * @param csTenantId 租户(商家)
     * @param lastCsId   最后服务的客服
     */
    public String csAlloc(String lastCsId, String csTenantId, String csOrgId) {
        JimCsSessionConfigResp config = FunctionUtils.getOkData(remoteCsSessionService.getConfig(csTenantId, SecurityConstants.FROM_IN));
        //客服可服务的最大人数
        Integer max = config.getMaxUser();
        //新用户接入的分配策略
        String distribution = config.getDistribution();
        //是否启用服务过的的客服优先分配
        Integer policyLastCs = config.getPolicyLastCs();
        //1.获取所有在线客服,如果没有在线,就创建一个临时会话  2.获取到所有空闲客服,没有空闲客服就进入排队  3.根据policyLastCs策略,分配客服 3.上一步分配失败,就根据新客户接入策略进行分配
        /***
         * 未实现分配逻辑,简单处理下
         */
        //获取在线客服/创建session
        List<String> userIdList = userHelper.getOnlineCsList(csTenantId, csOrgId);
        if (CollUtil.isNotEmpty(userIdList)) {
            //1.随机分配
            int index = (int) (Math.random() * userIdList.size());
            return userIdList.get(index);
        }
        /**
         * 没有分配到客服,就随机产生一个,随机产生的肯定是不在线,所以fade消息会进入离线消息
         */
        JimCsSession csSession = new JimCsSession();
        csSession.setCsTenantId(csTenantId);
        csSession.setCsOrgId(csOrgId);
        return createJwt(csSession);

    }


    public static String createJwt(JimCsSession resp) {
        JwtBuilder builder = Jwts.builder().setHeaderParam("session", "JWT")
                .claim("csTenantId", resp.getCsTenantId())
                .claim("userId", resp.getUserId())
                .claim("csId", resp.getCsId())
                .claim("sessionId", resp.getId())
                .claim("csOrgId", resp.getCsOrgId())
                .setIssuedAt(new Date())//设置签发时间
                .signWith(SignatureAlgorithm.HS256, "cs_session");//设置签名秘钥
        return builder.compact();
    }

    public static JimCsSession parseJWT(String token) {
        Claims claims = Jwts.parser().setSigningKey("cs_session").parseClaimsJws(token).getBody();
        JimCsSession session = new JimCsSession();
        if (claims == null) {
            return null;
        }
        session.setId(Convert.toStr(claims.get("sessionId")));
        session.setCsTenantId(Convert.toStr(claims.get("csTenantId")));
        session.setUserId(Convert.toStr(claims.get("userId")));
        session.setCsId(Convert.toStr(claims.get("csId")));
        session.setCsOrgId(Convert.toStr(claims.get("csOrgId")));
        return session;
    }
}
